package quoridor;

import java.util.Scanner;

public class TextDisplay implements GUI {
	
	private static final int BOARD_SIZE = 9;
	private static final int GAP_LEN = 4;
	private static final int INDENT = 2;
	private static final int NUM_OF_PARAM = 3;
	
	public TextDisplay () {
	}

	public Action getAction(PlayerColour colour) {
	   // Get player in a string for i/o
	   String player;
	   if (colour.equals(PlayerColour.BLACK))
	      player = "Black";
	   else
	      player = "White";
		Action newAction;
		Move newMove;
		String inputStr;
		while (true)
		{
			// request user input
			System.out.print(player+" player, please enter an action: ");
			try {
				Scanner INPUT = new Scanner (System.in);
				inputStr = INPUT.next();
			} catch (Exception e) {
				return null;
			} 
			// use regular expression to match the move string input
			if (inputStr.matches("\\p{Alpha}\\p{Digit}\\p{Alpha}?"))
			{
				newMove = Converter.stringToMove(inputStr, colour);
				newAction = new QuoridorAction(newMove);
				assert(newAction != null);
				break;
			}
			if (inputStr.equalsIgnoreCase("help"))
			{
				helpMenu();
				continue;
			}
			if (inputStr.equalsIgnoreCase("save"))
			{
				newAction = new QuoridorAction(ActionType.SAVE);
				assert(newAction != null);
				break;
			}
			if (inputStr.equalsIgnoreCase("exit"))
			{
				newAction = new QuoridorAction(ActionType.EXIT);
				assert(newAction != null);
				break;
			}
			if (inputStr.equalsIgnoreCase("undo"))
			{
				newAction = new QuoridorAction(ActionType.UNDO);
				assert(newAction != null);
				break;
			}
			if (inputStr.equalsIgnoreCase("redo"))
			{
				newAction = new QuoridorAction(ActionType.REDO);
				assert(newAction != null);
				break;
			}
			System.out.println("Input not recognised. Type help for a list of possible commands.");
		}
		
		
		return newAction;
	}
	
	public void printVictory(Board board, PlayerColour playerColour)
	{
	   String player;
	   if (playerColour.equals(PlayerColour.BLACK))
         player = "Black";
      else
         player = "White";
	   printBoard(board);
	   System.out.println(player+" player wins!");
	}
	
	private void playerSelectionMenu(int playerIndex) {
		System.out.println("---------------------");
		System.out.println("Player " + playerIndex + " Select");
		System.out.println("1: HUMAN");
		System.out.println("2: DUMB_AI");
		System.out.println("3: SMART_AI");
		System.out.println("4: RANDOM_AI");
		System.out.print("Choose: ");
	}
	
	
	public void mainMenu() {
		System.out.format("%15s\n", "Quoridor");
		System.out.println("---------------------");
		System.out.println("1: New Game");
		System.out.println("2: Load Game");
		System.out.println("3: Exit");
		System.out.print("Choose: ");
	}
	
	public void printBoard(Board board) {
		boolean[][] horizontalFences = board.getHorizontalFences();
		boolean[][] verticalFences = board.getVerticalFences();
		Coordinate playerBlack = board.getPlayerLocation(PlayerColour.BLACK);
		Coordinate playerWhite = board.getPlayerLocation(PlayerColour.WHITE);
		int rowCounter = 0;
		int blackHPos = playerBlack.getColumn();
		int blackVPos = playerBlack.getRow();
		int whiteHPos = playerWhite.getColumn();
		int whiteVPos = playerWhite.getRow();

		System.out.println("Black player fences remaining: "+board.getFenceNum(PlayerColour.BLACK));
		System.out.println("White player fences remaining: "+board.getFenceNum(PlayerColour.WHITE));
		
		for (int i = 0; i < BOARD_SIZE * 4 + 3; ++i) {
			if (i > 1) {
				System.out.print('-');
			} else {
				System.out.print(' ');
			}
		}
		System.out.println();

		// actual board
		for (int i = 0; i < BOARD_SIZE * 2 - 1; ++i) {
			if (i % 2 == 1) {
				// print top line
				for (int j = 0; j < BOARD_SIZE * GAP_LEN + INDENT + 1; ++j) {
					if (j == INDENT || j == BOARD_SIZE * GAP_LEN + INDENT) {
						System.out.print('|');
					} else if (j > INDENT && (j % GAP_LEN == 0 || (j - 1) % GAP_LEN == 0 || 
						(j + 1) % GAP_LEN == 0)) {
						// check if horizontal walls need to be placed
						if (horizontalFences[rowCounter - 1][(j + 1)/GAP_LEN - 1] == true) {
							System.out.print('-');
						} else {
							System.out.print(' ');
						}
					} else {
						// fill the gap between two wall coordiantes
						// if the gap is between two horizontal fences positions
						if ((j > INDENT) && horizontalFences[rowCounter - 1][(j + 1)/GAP_LEN - 1] == true 
							&& ((j + 2)/GAP_LEN - 1 < BOARD_SIZE) && 
							horizontalFences[rowCounter - 1][(j + 2)/GAP_LEN - 1] == true) {
							System.out.print('+');
						} else if ((j > INDENT) && verticalFences[(j - 2)/GAP_LEN - 1][rowCounter - 1] == true
							&& (rowCounter < BOARD_SIZE) && 
							verticalFences[(j - 2)/GAP_LEN - 1][rowCounter] == true) {
							// if the gap is between two vertical fences positions
							System.out.print('|');
						} else {
							System.out.print(' ');
						}
					}
				}
			} else {
				for (int j = 0; j < BOARD_SIZE * GAP_LEN + INDENT + 1; ++j) {
					if (j == 0) {
						// print vertical row index
						System.out.print(i / 2 + 1);
					} else if (j == INDENT || j == BOARD_SIZE * GAP_LEN + INDENT) {
						// print side wall
						System.out.print('|');
					} else if ((j > INDENT) && (j % GAP_LEN == 0)) {
						// print the position of square
						// check if it is occupied
						if (j / GAP_LEN - 1 == blackHPos && rowCounter == blackVPos) {
							System.out.print('B');
						} else if (j / GAP_LEN - 1 == whiteHPos && rowCounter == whiteVPos) {
							System.out.print('W');
						} else {
							System.out.print('.');
						}
					} else if ((j > INDENT)  && ((j - 2) % GAP_LEN == 0)) { 
						if (verticalFences[(j - 2) / GAP_LEN - 1][rowCounter] == true) {
							System.out.print('|');
						} else {
							System.out.print(' ');
						}
					} else {
						System.out.print(' ');
					}
				}
				++rowCounter;
			}
			System.out.println();
		}
		
		// print bottom line
		for (int k = 0; k < BOARD_SIZE * GAP_LEN + INDENT + 1; ++k) {
			if (k > 1) {
				System.out.print('-');
			} else {
				System.out.print(' ');
			}
		}
		
		System.out.println();
		for (int i = 0; i < BOARD_SIZE * GAP_LEN + INDENT + 1; ++i) {
			if (i != 0 && i % GAP_LEN == 0) {
				char temp = (char) ((i + 1) / GAP_LEN + 96);
				System.out.print(temp);
			} else {
				System.out.print(' ');
			}
		}
		System.out.println();
	}
	
	private void invalidMessage()
	{
		System.out.println("Please choose an option on the list");
	}
	
	/**
	 * Test whether or not a sting is an integer
	 * @param inputStr from the scanner
	 * @return boolean indicating whether or not the string is an integer
	 */
	private boolean isInt(String inputStr) {
		try {
			Integer.parseInt(inputStr);
			return true;
		} catch (Exception exception) {
			return false;
		}
	}

	private int getInput(int lower, int upper) {
		int choice;
		String inputStr;
		Scanner INPUT = new Scanner (System.in);
		while(true) {
			// get in if the input is invalid
			try {
				INPUT.hasNext();
				inputStr = INPUT.next();
				// test if the input is an integer
				if (isInt(inputStr)) {
					choice = Integer.parseInt(inputStr);
					if (choice >= lower && choice <= upper) {
						break;
					}
				}
				invalidMessage();
				System.out.print("Choose: ");
			} catch (Exception e) {
				return 0;
			}
		}
		return choice;
	}
	

	public int [] initialSetup() {
		int [] gameParam = new int[NUM_OF_PARAM];
		mainMenu();
		gameParam[0] = getInput(1,3);
		GameType theGameType = GameType.values()[gameParam[0] - 1];
		switch(theGameType) {
			case NEWGAME:
				prompt (gameParam);
				break;
			case LOADGAME:
				prompt (gameParam);
				break;
			case EXITGAME:
				return gameParam;
			default:
				throw new IllegalStateException ("panic: game state is wrong");		
		}
		return gameParam;
	}
	
	private void prompt (int[] gameParam) {
		playerSelectionMenu(1);
		gameParam[1] = getInput(1,4);
		playerSelectionMenu(2);
		gameParam[2] = getInput(1,4);
	}


	@Override
	public void exitGameMessage() {
		System.out.println("Game has been exited");
		System.out.println("See you next time");
	}


	@Override
	public void invalidMove() {
		System.out.println("Invalid move - check your input.");
	}
	
	private void helpMenu() {
		System.out.println("---------------------");
		System.out.println("The following input strings are allowed:");
		System.out.println("\tMove your piece: for instance \"e4\"");
		System.out.println("\tPlace a fence: for instance \"e4h\"");
		System.out.println("\tHelp");
		System.out.println("\tSave");
		System.out.println("\tUndo");
		System.out.println("\tRedo");
		System.out.println("\tExit");
	}
}